import time
import sys
import os
import argparse
import random
import threading
import termios  # 原生终端控制模块
import tty      # 终端模式控制
import select
from abc import ABC, abstractmethod

sys.path.append(os.path.dirname(os.path.dirname(__file__)))

from .service.rgb import RGBService
from .service.base import Priority

DEBUG=False
def debug_print(*args,**kwargs):
    if DEBUG:
        print(*args,**kwargs)        

# 动作抽象基类
class Action(ABC):
    def __init__(self,tips):
        self.tips=tips

    def getTips(self):
        return self.tips

    @abstractmethod
    def execute(self, controller):
        pass

# 具体动作
class IncreaseBrightnessAction(Action):
    def __init__(self,tipString):
        super().__init__(tipString)

    def execute(self, controller):
        controller.brightness = min(1.0, controller.brightness + controller.getBrightnessDelta())
        debug_print(f"[调试] 亮度增加到: {controller.brightness:.1f}")
        if controller.brightness==1.0:
            print("\rLED亮度已经最大.")

class DecreaseBrightnessAction(Action):
    def __init__(self,tipString):
        super().__init__(tipString)

    def execute(self, controller):
        controller.brightness = max(0.0, controller.brightness - controller.getBrightnessDelta())
        debug_print(f"[调试] 亮度减少到: {controller.brightness:.1f}")
        if controller.brightness==0.0:
            print("\rLED亮度最小,关闭.")

class StopAction(Action):
    def __init__(self,tipString):
        super().__init__(tipString)

    def execute(self, controller):
        debug_print("\n[调试] 收到退出命令，设置running=False")
        controller.running = False

class ApplyBrightnessAction(Action):
    def __init__(self, color):
        self.color = color
    def execute(self, controller):
        if not self.color:
            return None
        return tuple(int(c * controller.brightness) for c in self.color)

class RGBLightController:
    def __init__(self, total_LEDs,origin_brightness=0.5,brightness_delta=0.1,initial_color=None):
        self.total_LEDs = total_LEDs
        self.rgb_service = RGBService()

        self.brightness_delta=brightness_delta
        self.brightness = max(min(1.0,origin_brightness),0.0)

        self.initial_color = initial_color
        self.running = True
        self.key_actions = {}
        self.paint_colors = []
        self.rgb_thread = None

        self.fd = sys.stdin.fileno()  # 获取标准输入文件描述符
        self.old_settings = termios.tcgetattr(self.fd)  # 保存原始终端设置

    def getBrightnessDelta(self):
        return self.brightness_delta

    def register_keys(self, keys, action):
        if isinstance(action, Action):
            for key in keys:
                self.key_actions[key] = action  # 直接用原始按键字符匹配
                debug_print(f"[调试] 注册按键: {key} -> {action.__class__.__name__}")

    def _run_rgb_service(self):
        debug_print("[调试] RGB服务线程启动，执行rgb_service.start()")
        try:
            self.rgb_service.start()
            debug_print("[调试] RGB服务启动完成")
        except Exception as e:
            debug_print(f"[错误] RGB服务启动失败: {str(e)}", file=sys.stderr)

    def _set_terminal_raw(self):
        """将终端设置为原始模式（无缓冲、无回显，按键立即响应）"""
        tty.setraw(self.fd)
        # 禁用回显（可选，避免按键显示在屏幕上）
        new_settings = termios.tcgetattr(self.fd)
        new_settings[3] &= ~termios.ECHO  # 清除ECHO标志
        termios.tcsetattr(self.fd, termios.TCSADRAIN, new_settings)

    def _restore_terminal(self):
        """恢复终端原始设置"""
        termios.tcsetattr(self.fd, termios.TCSADRAIN, self.old_settings)

    def _get_help_string(self,seperator="/"):
        action2keys = {}
        for key,action in self.key_actions.items():
            if not action2keys.get(action):
                action2keys[action] = [key]
            else:
                action2keys[action].append(key)
        help_string=[]
        for action,keys in action2keys.items():
            help_string.append(seperator.join(keys) + ":" + action.getTips())
        
        return help_string
        
    
    def run(self):
        print("=== RGB灯控制器（原生按键版）启动 ===")
        print("操作说明：")
        help_tips=self._get_help_string(seperator="/")
        print("\n".join(["  按 "+s for s in help_tips ]))
        print("注意：直接按按键即可，无需回车\n")

        # 启动RGB服务线程
        self.rgb_thread = threading.Thread(target=self._run_rgb_service, daemon=True)
        self.rgb_thread.start()
        debug_print("[调试] 等待RGB服务初始化...")
        time.sleep(2)

        try:
            # 设置终端为原始模式（关键！实现无缓冲输入）
            self._set_terminal_raw()
            debug_print("[调试] 终端已设置为原始模式，等待按键...")

            loop_counter = 0
            while self.running:
                loop_counter += 1
                if loop_counter % 50 == 0:
                    debug_print(f"[调试] 主循环运行中 | 次数: {loop_counter} | 亮度: {self.brightness:.1f}")

                # 读取按键（非阻塞，超时0.01秒）
                # 1. 检查按键输入（非阻塞）
                if select.select([sys.stdin], [], [], 0.01)[0]:
                    key = sys.stdin.read(1)  # 读取单个字符（无需回车）
                    debug_print(f"\n[调试] 检测到按键: {repr(key)}")
                    
                    # 处理特殊按键（如退格、ESC等，可选）
                    if ord(key) == 3:  # Ctrl+C
                        debug_print("[调试] 检测到Ctrl+C，强制退出")
                        self.running = False
                    elif key in self.key_actions:
                        self.key_actions[key].execute(self)
                    else:
                        debug_print(f"[调试] 未注册按键: {repr(key)} (ASCII: {ord(key)})")

                # 2. 处理颜色输出
                if self.initial_color and self.running:
                    adjusted_color = ApplyBrightnessAction(self.initial_color).execute(self)
                    self.rgb_service.dispatch("solid", adjusted_color)
                    time.sleep(0.1)
                elif self.running:
                    self.paint_colors.append((
                        random.randint(0, 255),
                        random.randint(0, 255),
                        random.randint(0, 255)
                    ))
                    if len(self.paint_colors) == self.total_LEDs:
                        adjusted_colors = [ApplyBrightnessAction(c).execute(self) for c in self.paint_colors]
                        self.rgb_service.dispatch("paint", adjusted_colors)
                        time.sleep(0.2)
                        self.paint_colors.pop(0)

                time.sleep(0.05)

        except Exception as e:
            print(f"\n[错误] 主循环异常: {str(e)}", file=sys.stderr)
        finally:
            # 必须恢复终端设置，否则终端会异常
            self._restore_terminal()
            debug_print("\n[调试] 终端已恢复原始模式")
            
            # 清理其他资源
            self.running = False
            self.rgb_service.stop()
            if self.rgb_thread and self.rgb_thread.is_alive():
                self.rgb_thread.join(timeout=3)
            debug_print("[调试] 程序完全退出")


def parse_color(color_str):
    try:
        r, g, b = map(int, color_str.split(','))
        if all(0 <= x <= 255 for x in [r, g, b]):
            return (r, g, b)
        raise ValueError("颜色值必须在0-255之间")
    except ValueError as e:
        raise argparse.ArgumentTypeError(f"无效格式: {color_str}，示例'255,0,0'") from e

# 初始亮度验证函数（0.0-1.0）
def valid_brightness(value):
    f_val = float(value)
    if not (0.0 <= f_val <= 1.0):
        raise argparse.ArgumentTypeError(f"初始亮度必须在0.0-1.0之间，当前输入: {value}")
    return f_val

# 亮度变化步长验证函数（>0）
def valid_change_delta(value):
    f_val = float(value)
    if f_val <= 0 or f_val>=1.0:
        raise argparse.ArgumentTypeError(f"亮度变化步长必须大于0，当前输入: {value}")
    return f_val

# 主程序入口
if __name__ == "__main__":
    TOTAL_LED_NUM = 16  # 总LED数量

    # 命令行参数解析
    parser = argparse.ArgumentParser(description='RGB灯控制器（原生按键版）')
    # 颜色互斥参数组
    color_group = parser.add_mutually_exclusive_group()
    color_group.add_argument('--color', type=parse_color, help='指定RGB颜色，格式"r,g,b"（如255,0,0）')
    color_group.add_argument('--random-color', action='store_true', help='使用随机固定颜色')
    # 亮度控制参数
    parser.add_argument(
        '--brightness',
        type=valid_brightness,
        default=0.5,
        help='初始亮度（0.0-1.0，默认0.5，例：--brightness 0.8）'
    )
    parser.add_argument(
        '--change-delta',
        type=valid_change_delta,
        default=0.1,
        help='亮度变化步长（>0，默认0.1，例：--change-delta 0.05）'
    )

    # 解析参数
    args = parser.parse_args()
    initial_color = None
    if args.random_color:
        initial_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
        debug_print(f"[调试] 随机颜色模式：{initial_color}")
    elif args.color:
        initial_color = args.color
        debug_print(f"[调试] 指定颜色模式：{initial_color}")
    else:
        debug_print("[调试] 默认模式：随机颜色序列")

    # 创建控制器实例并启动
    controller = RGBLightController(
        total_LEDs=TOTAL_LED_NUM,
        origin_brightness=args.brightness,
        brightness_delta=args.change_delta,
        initial_color=initial_color
    )
    # 注册按键（x/q退出，+/-增减亮度）
    controller.register_keys('xq', StopAction("退出程序"))
    controller.register_keys('+=', IncreaseBrightnessAction("增加亮度"))
    controller.register_keys('-_', DecreaseBrightnessAction("减少亮度"))

    # 启动控制器
    controller.run()